using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.ETL
{
    /// <summary>
    /// SYNC TABLE BY UNIQUE KEY (CAN BE COMPOSITE), TIMESTAMP (CANNOT REMOVE) OR STREAM REFRESH
    /// ALLOW CUSTOM FIELD MAPPINGS
    /// </summary>
    [Serializable]
    public class SyncDbTableInstruction:InstructionBase
    {
        #region props
        private DataProviderType _SrcDbProvider;
        /// <summary></summary>
        public DataProviderType SrcDbProvider
        {
            get { return _SrcDbProvider; }
            set { _SrcDbProvider = value; }
        }
        private string _SrcConnStr;
        /// <summary></summary>
        public string SrcConnStr
        {
            get { return _SrcConnStr; }
            set { _SrcConnStr = value; }
        }
        
        private string _SrcSchema;
        /// <summary></summary>
        public string SrcSchema
        {
            get { return _SrcSchema; }
            set { _SrcSchema = value; }
        }

        private string _SrcTblName;
        /// <summary></summary>
        public string SrcTblName
        {
            get { return _SrcTblName; }
            set { _SrcTblName = value; }
        }

        private bool _UseSql;
        /// <summary></summary>
        public bool UseSql
        {
            get { return _UseSql; }
            set { _UseSql = value; }
        }

        private string _SelectStatement;
        /// <summary></summary>
        public string SelectStatement
        {
            get { return _SelectStatement; }
            set { _SelectStatement = value; }
        }
	

        private List<string> _SrcTableUniqueKeys;
        /// <summary></summary>
        public List<string> SrcTableUniqueKeys
        {
            get { return _SrcTableUniqueKeys; }
            set { _SrcTableUniqueKeys = value; }
        }

        private string _SrcTimeStampField;
        /// <summary></summary>
        public string SrcTimeStampField
        {
            get { return _SrcTimeStampField; }
            set { _SrcTimeStampField = value; }
        }

        private DataProviderType _TgtDbProvider;
        /// <summary></summary>
        public DataProviderType TgtDbProvider
        {
            get { return _TgtDbProvider; }
            set { _TgtDbProvider = value; }
        }

        private string _TgtConnStr;
        /// <summary></summary>
        public string TgtConnStr
        {
            get { return _TgtConnStr; }
            set { _TgtConnStr = value; }
        }

        private string _TgtTableName;
        /// <summary></summary>
        public string TgtTableName
        {
            get { return _TgtTableName; }
            set { _TgtTableName = value; }
        }

        private Dictionary<string,string> _FieldMappings;
        /// <summary></summary>
        public Dictionary<string,string> FieldMappings
        {
            get
            {
                return this._FieldMappings;
            }
            set
            {
                this._FieldMappings = value;
            }
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        public SyncDbTableInstruction():base(Guid.Empty, Guid.Empty)
        {
            this.SrcDbProvider = DataProviderType.Oracle;
            this.SrcConnStr = string.Empty;
            this.SrcSchema = string.Empty;
            this.SrcTblName = string.Empty;
            this.SrcTableUniqueKeys = null;
            this.SrcTimeStampField = string.Empty;
            this.UseSql = false;
            this.SelectStatement = string.Empty;

            this.TgtDbProvider = DataProviderType.MSSQL;
            this.TgtConnStr = string.Empty;
            this.TgtTableName = string.Empty;
            this.FieldMappings = null;
        }

        /// <summary></summary>
        public SyncDbTableInstruction(
            Guid componentID, Guid jobTicketID,
            DataProviderType srcDbProvider,
            string srcConnStr,
            string srcSchema,
            string srcTbl,
            bool useSql,
            string selectStatement,
            List<string> srcUniqueKeyFieldNames,
            string srcTimestampFieldName,
            DataProviderType tgtDbProvider,
            string tgtConnStr,
            string tgtTblName,
            Dictionary<string,string> fieldMappings) 
            : base(componentID, jobTicketID)
        {
            this.SrcDbProvider = srcDbProvider;
            this.SrcConnStr = srcConnStr;
            this.SrcSchema = srcSchema;
            this.SrcTblName = srcTbl;
            this.UseSql = useSql;
            this.SelectStatement = selectStatement;
            this.SrcTableUniqueKeys = srcUniqueKeyFieldNames;
            this.SrcTimeStampField = srcTimestampFieldName;

            this.TgtDbProvider = tgtDbProvider;
            this.TgtConnStr = tgtConnStr;
            this.TgtTableName = tgtTblName;
            this.FieldMappings = fieldMappings;
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcDbProvider", ((int) this.SrcDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcConnStr", this.SrcConnStr.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcSchema", this.SrcSchema);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"UseSql",this.UseSql.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"SelectStatement",this.SelectStatement);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcTblName", this.SrcTblName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcTableUniqueKeys",
                                        StringUtil.ToString(this.SrcTableUniqueKeys == null
                                                                ? null
                                                                :
                                                                    this.SrcTableUniqueKeys.ToArray()));
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcTimeStampField", this.SrcTimeStampField);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtDbProvider", ((int) this.TgtDbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtConnStr", this.TgtConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtTableName", this.TgtTableName);

            if(this.FieldMappings !=null && this.FieldMappings.Count>0)
            {
                XmlNode fieldMappingRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "FieldMappings");
                foreach(string srcFieldName in this.FieldMappings.Keys)
                {
                    XmlNode fieldMappingNode = XmlDataUtil.AddElement(ref xDoc, fieldMappingRootNode, "FieldMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc,fieldMappingNode,"SrcFieldName",srcFieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldMappingNode, "TgtFieldName",
                                                this.FieldMappings[srcFieldName]);
                }
            }

            return xNode;
        }

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                SyncDbTableInstruction instruction = new SyncDbTableInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.SrcDbProvider =
                    (DataProviderType) int.Parse(xNode.Attributes.GetNamedItem("SrcDbProvider").Value);
                instruction.SrcConnStr = xNode.Attributes.GetNamedItem("SrcConnStr").Value;
                instruction.SrcSchema = xNode.Attributes.GetNamedItem("SrcSchema").Value;
                instruction.SrcTblName = xNode.Attributes.GetNamedItem("SrcTblName").Value;
                instruction.UseSql = bool.Parse(xNode.Attributes.GetNamedItem("UseSql").Value);
                instruction.SelectStatement = xNode.Attributes.GetNamedItem("SelectStatement").Value;
                instruction.SrcTableUniqueKeys = null;
                string[] uniqueKeys = StringUtil.Split(xNode.Attributes.GetNamedItem("SrcTableUniqueKeys").Value);
                if (uniqueKeys != null && uniqueKeys.Length > 0)
                {
                    instruction.SrcTableUniqueKeys = new List<string>();
                    foreach (string uniqueKey in uniqueKeys)
                    {
                        instruction.SrcTableUniqueKeys.Add(uniqueKey);
                    }
                }
                instruction.SrcTimeStampField = xNode.Attributes.GetNamedItem("SrcTimeStampField").Value;

                instruction.TgtDbProvider =
                    (DataProviderType) int.Parse(xNode.Attributes.GetNamedItem("TgtDbProvider").Value);
                instruction.TgtConnStr = xNode.Attributes.GetNamedItem("TgtConnStr").Value;
                instruction.TgtTableName = xNode.Attributes.GetNamedItem("TgtTableName").Value;
                instruction.FieldMappings = null;
                XmlNodeList fieldMappingNodes = xNode.SelectNodes("FieldMappings/FieldMapping");
                if(fieldMappingNodes !=null && fieldMappingNodes.Count>0)
                {
                    instruction.FieldMappings=new Dictionary<string, string>();
                    foreach(XmlNode fieldMappingNode in fieldMappingNodes)
                    {
                        string srcFieldName = fieldMappingNode.Attributes.GetNamedItem("SrcFieldName").Value;
                        string tgtFieldName = fieldMappingNode.Attributes.GetNamedItem("TgtFieldName").Value;
                        instruction.FieldMappings.Add(srcFieldName,tgtFieldName);
                    }
                }

                return instruction;
            }
            else
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
        }
    }
}
